#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import SocketServer
import threading
import time
from re import search

class ChatServerManager():
    
    SERVEUR_DESCRIPTION = "Serveur de Chat par telnet 0.1"
    SERVEUR_ACCEPT_CMD = ('help', 'user', 'nick', 'me', 'quit', 'kill_serv')
    stopped = False
    
    #Dictionnaire des threads cliente
    __thread_dict = {}
    
    def __init__(self, port, host):
        #Initialise le serveur         
        print self.SERVEUR_DESCRIPTION
        print 'Demarage du serveur sur ', host, ':', str(port), '\r\n'
        #Demarage du serveur
        self.server = SocketServer.ThreadingTCPServer((str(host), int(port)), 
                                                      ChatServeurHandler)
    def format_msg(self, msg_item):
        #Formate un message de sortie 
        formated_message = ''
        for i in msg_item:
            formated_message += "%s \r\n" % (i)  
        return formated_message
    
    def kill_server(self):
        '''
        Ferme et arrete le serveur
        TODO: a tester         
        '''
        self.server.__is_shut_down.set()
        #self.server.server_close()
        self.server.stopped = True
       
    def add_client(self, cli_thread):
        print cli_thread.client_address, 'Connexion cliente !'
        #Chargement de la connexion cliente
        self.__thread_dict[cli_thread.id] = {'HOST' : cli_thread.host,
                                             'NICK' : None,
                                             'UPSINCE' : 2009, #TODO: mettre le timestamp courant
                                             'HANDLER' : cli_thread }
        #Construction du message de bienvenue        
        wellcome_mgs = self.format_msg(('-' * 50, 
                                         self.SERVEUR_DESCRIPTION,
                                         '',
                                         'Host     : ' + cli_thread.host,
                                         'Nb. User : ' + str(len(self.__thread_dict)),
                                         '-' * 50,
                                         'Saisissez votre pseudo :'))
        #envoi du message de connexion au client
        cli_thread.send_message(wellcome_mgs)
    
    def del_client(self, id_thread):
        print id_thread, 'se deconnect'
        del self.__thread_dict[id_thread]
    
    def client_validate(self, client_id, client_line):
        return_code = True
        #La premiere entre client est le Nick
        if self.__thread_dict[client_id]['NICK'] == None:
            self.__thread_dict[client_id]['NICK'] = client_line
            self.send_message(0, 'Votre pseudo est : ' + client_line + '\r\n', client_id)
            print client_id, 'est maintenant ' + client_line
            return
        
        if client_line[:1] == "/":
            #Si c'est une commande serveur
            return_code = self.exec_commande(client_id, client_line[1:])              
        else:
             #envoi du message a tout le monde
            self.send_message(client_id, client_line, 0)
        return return_code
    
    def send_message(self, mfrom, line, to):
        if mfrom > 0:
            print 'Message de %s > %s' % (self.__thread_dict[mfrom]['NICK'], line)
        message_line = ''
        #Si id de client presise        
        if to > 0:
            #si mfrom a 0 > message du serveur
            if mfrom == 0: message_line = '<%s> %s' % ('ServerManager', line)
            else : message_line = '<%s> %s' % (self.__thread_dict[mfrom]['NICK'], line)
            self.__thread_dict[to]['HANDLER'].send_message(message_line)
        else:
            #si pas id de client presise
            for i in self.__thread_dict:
                if i != mfrom:
                    message_line = '<%s> %s' % (self.__thread_dict[mfrom]['NICK'], line)
                    self.__thread_dict[i]['HANDLER'].send_message(message_line)
    
    def exec_commande(self, cfrom, cmd_string):
        print 'Commande de %s > %s' % (self.__thread_dict[cfrom]['NICK'], cmd_string)
        #Traitement de la chaine commande
        cmd_word = cmd_string.split(' ')
        cmd_string = ''
        cmd_return = ''
        #si la commande est acceptee
        if cmd_word[0] in self.SERVEUR_ACCEPT_CMD:
            #construction de la commande
            cmd_string = 'cmd_return = self.cmd_' + cmd_word[0] + '(' + str(cfrom)
            for w in cmd_word[1:]:
                cmd_string += ", '" + w + "'"
            cmd_string += ')'
            try:
                #execution de la commande
                exec(cmd_string)
            except:
                self.send_message(0, 'Erreur : erreur de syntaxe dans la commande'  , cfrom)           
        else:
            self.send_message(0, 'Erreur : commande inconue !'  , cfrom)
        return cmd_return
        
    '''
    Methodes de commandes serveur
    ''' 
    def cmd_help(self, client):
        help_commades = 'Liste des commandes serveur :'
        for h in self.SERVEUR_ACCEPT_CMD:
            help_commades += '\r\n /' + h
        #envoi du resultat au client
        self.send_message(0, help_commades, client)
        return True 
                
    def cmd_user(self, client):
        client_list = 'Utilisateurs actif :'
        for c in self.__thread_dict:
            client_list += '\r\n- ' + self.__thread_dict[c]['NICK']
        #envoi du resultat au client
        self.send_message(0, client_list, client)
        return True
        
    def cmd_nick(self, client, new_name):
        print self.__thread_dict[client]['NICK'], 'est maintenant ' + new_name
        self.__thread_dict[client]['NICK'] = new_name
        client_new = 'Votre nouveau pseudo est : ' + new_name
        self.send_message(0, client_new, client)
        return True
        
    def cmd_me(self, client):
        client_name = 'Vous etes : ' + self.__thread_dict[client]['NICK']
        self.send_message(0, client_name, client)
        return True
    
    def cmd_quit(self, client):
        self.send_message(0, 'Vous etes maintenant deconnecte', client)
        return 'CLOSE_CONNEXION'
    
    def cmd_kill_serv(self, client):
        self.send_message(0, 'C\'est sa ouai, et les droit admin tu les as ?!', client)
        self.kill_server()
        return True


class ChatServeurHandler(SocketServer.BaseRequestHandler):
    
    #ligne courante du client
    client_line = ""
    
    def setup(self):
        self.host = str(self.client_address[0])
        self.id = int(self.client_address[1]) #peut etre le port ?
        #Enregistrement de la thread client
        myChatServ.add_client(self)
        
    def handle(self):
        while 1:
            #recuperation de l'entree cliente
            data = self.request.recv(1024)
            #Si l'entree courante est un retour chariot
            if search('\n$', data): # == '\r\n' or data == '\n':
                if data != '\r\n':
                    self.client_line += data[:-2]
                #envois d'un message
                r = myChatServ.client_validate(self.id, self.client_line)
                if r == 'CLOSE_CONNEXION':
                    #Termine la thread cliente
                    return
                else:
                    #vide la ligne cliente apres validation
                    self.client_line = ""
            else:
                #stockage dans la ligne courante
                self.client_line += data
                
    def send_message(self, msg_string):
        #Envois du message au client
        self.request.send('\r\n' + msg_string + '\r\n')

    def finish(self):
        #suppression de la thread cliente comme thread active
        myChatServ.del_client(self.id)
        
       
        
if __name__ == '__main__':
    #creation et lancement du serveur
    myChatServ = ChatServerManager(2008, 'localhost')
    myChatServ.server.serve_forever()

    

 